package com.ccll.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ccll.constants.GlobalConstant;
import com.ccll.domain.common.BaseContextHolder;
import com.ccll.domain.dto.LoginUser;
import com.ccll.domain.po.User;
import com.ccll.mapper.UserMapper;
import com.ccll.service.UserService;
import com.ccll.utils.JwtUtil;
import com.ccll.utils.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Seon
 * @date 2022/11/12 10:23
 */
@Slf4j
@Service
public class UserServiceImpl
        extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private ApplicationContext applicationContext;
    // 也可以实现ApplicationContextAware接口，然后把里面的applicationContext获取到，再给到类中的static 变量即可。

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    @Transactional
    public boolean signup(User user) {
        String password = user.getPassword();
        password = passwordEncoder.encode(password);
        user.setPassword(password);
        user.setStatus("0");
        user.setSex("2");
        this.save(user);
        return true;
        // proxyU.signup -> U.signup -> proxyU.save -> U.save  有事务
        // proxyU.signup -> U.signup -> U.save  没有事务
    }

    /**
     * 1. 进行对应的认证，没过的话给出对应的提示
     * 2. 认证通过了，就用userid生成一个token
     * 3. 把完整的信息存入redis，userid作为key，用户信息作为value
     */
    @Override
    public String login(User user) {
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());

        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        if (authenticate == null) {
            throw new RuntimeException("登录失败");
        }
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        User success = loginUser.getUser();
        //生成token
        String token = JwtUtil.createJWT(success.getId().toString(), success.getPassword(), JwtUtil.JWT_TTL);
        //存入redis
        String redisKey = GlobalConstant.USER_LOGIN + success.getId();
        redisCache.setCacheObject(redisKey, loginUser);
        log.info("id = {}，用户登录成功", success.getId());
        return token;
    }

    @Override
    public boolean logout() {
        Long id = BaseContextHolder.getCurrentId();
        String redisKey = GlobalConstant.USER_LOGIN + id;
        if (redisCache.deleteObject(redisKey)) {
            log.info("id = {}, 用户已经下线了", id);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public User getUserByName(String username) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, username);
        User user = this.getOne(wrapper);
        return user;
    }

    @Override
    @Transactional
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        try {
            Map<String, Object> map = new HashMap<>(2);
            idList.forEach(id -> {
                super.removeById(id);
                map.put("userId", id);
                userMapper.deleteUserRole(map);
            });
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    @Transactional
    public boolean save(User entity) {
        super.save(entity);
        Map<String, Object> map = new HashMap<>(2);
        map.put("userId", entity.getId());
        map.put("roleId", GlobalConstant.USER_ROLE_ID);
        userMapper.addUserRole(map);
        return true;
    }

    /**
     * 子事务抛出异常测试Propagation.REQUIRES_NEW测试方法
     * @param entity
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public boolean saveUserRoleTest(User entity) {
        // 验证方法： 在父里面操作用户，插入用户数据，在子里面插入用户角色的数据。
        Map<String, Object> map = new HashMap<>(2);
        map.put("userId", entity.getId());
        map.put("roleId", GlobalConstant.USER_ROLE_ID);
        userMapper.addUserRole(map);
        throw new RuntimeException();
    }

//    /**
//     * 获取到Spring的bean
//     * @param applicationContext
//     * @throws BeansException
//     */
//    @Override
//    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//
//    }
}
